#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// define Wave format structure
/// wav格式的subChunk1的“fmt”部分，一般是16字节
typedef struct tWAVEFORMATEX
{
    short wFormatTag;
    short nChannels;
    unsigned int nSamplesPerSec;
    unsigned int nAvgBytesPerSec;
    short nBlockAlign;
    short wBitsPerSample;
    short cbSize;  ///这两个字节，无用
} WAVEFORMATEX, *PWAVEFORMATEX;

// read wave file
int read_wav(const char *fname, WAVEFORMATEX *wf, const char * outpcmfile)
{
    FILE* fp = nullptr;
    FILE* fpOutPCM = nullptr;
    char str[32] = {0};
    char *speech = nullptr;
    unsigned int subchunk1size  = 0; // head size
    unsigned int subchunk2size  = 0; // speech data size
    // check format type
    fp = fopen(fname,"r");
    if(!fp)
    {
        fprintf(stderr,"Can not open the wave file: %s.\n",fname);
        return -1;
    }

    fpOutPCM = fopen(outpcmfile, "wb");
    if(!fpOutPCM)
    {
        fprintf(stderr,"Can not open the out.pcm file: %s.\n",outpcmfile);
        return -1;
    }

    /// 跳过前8个字节
    fseek(fp, 8, SEEK_SET);

    // 读接下来的连续的7个字节,检查是否是WAVEfmt
    fread(str, sizeof(char), 7, fp);
    str[7] = '\0';
    if(strcmp(str,"WAVEfmt"))
    {
        fprintf(stderr,"The file is not in WAVE format!\n");
        return -1;
    }
    // read format header
    fseek(fp, 16, SEEK_SET);///定位函数

    /// subChunk1Size: 一般wav文件，这里对应的是16字节。 有的时候不是16字节
    fread((unsigned int*)(&subchunk1size),4,1,fp); ///小端字节序，读4个字节，子块的字节数

    fseek(fp, 20, SEEK_SET);
    fread(wf, subchunk1size, 1, fp);
    // read wave data
    fseek(fp, 20+subchunk1size, SEEK_SET);
    fread(str, 1, 4, fp);
    str[4] = '\0';

    if(strcmp(str,"data"))
    {
        fprintf(stderr,"Locating data start point failed!\n");
        return NULL;
    }

    fseek(fp, 20+subchunk1size+4, SEEK_SET);
    fread((unsigned int*)(&subchunk2size), 4, 1, fp); //真实的PCM裸数据的大小
    speech = (char*)malloc(sizeof(char)*subchunk2size);
    if(!speech)
    {
        fprintf(stderr, "Memory alloc failed!\n");
        return -1;
    }
    //读取data字段到缓存
    fseek(fp, 20+subchunk1size+8, SEEK_SET);
    fread(speech, 1, subchunk2size, fp);
    fclose(fp);
    fp = nullptr;
    //data输出到文件
    fwrite(speech, 1, subchunk2size, fpOutPCM);

    fclose(fpOutPCM);
    fpOutPCM = nullptr;
    free(speech);
    speech = nullptr;

    return 0;
}

int main(int argc, const char* argv[])
{
    const char* fname = "../resource/10s_s16le-44100-ch2.wav";
    int result;
    WAVEFORMATEX wf;
    result = read_wav(fname, &wf, "audio.pcm");
    // afterward processing...
    return 0;
}
